package cn.openea.perpartner.mpwx.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import me.chanjar.weixin.mp.api.WxMpService;
import cn.openea.perpartner.mpwx.core.WxServiceTemplate;
import cn.openea.perpartner.mpwx.service.IWxMpMediaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;

/**
 * @author Weird077
 * @description 生成推荐二维码并上传到公众号换取图片素材media_id
 * @date 2022-06-20 22:19
 */
@Service
public class WxMpMediaServiceImpl implements IWxMpMediaService {
    /**
     * WxServiceInf
     */
    @Autowired
    private WxServiceTemplate wxServiceTemplate;

    @Override
    public String run(HashMap<String, Object> params) throws Exception {
        // 初始化实例
        WxMpService wxMpService = wxServiceTemplate.getWxMpService();

        // 获取授权码
        String access_token = wxMpService.getAccessToken(true);
        // 操作者的openid
        String fromUserName = (String) params.get("fromUserName");
        // 指定小程序中的用户名
        String regOpenid = (String) params.get("regOpenid");
        // 获取的类型，这里如果有值且等于qrurl时表示只获取二维码地址
        String getType = (String) params.get("getType");
        // 获取二维码ticket
        String ticket = getQrCodeTicket(access_token, fromUserName, regOpenid);
        // 获取二推荐的二维码图片的接口地址，这里返回的是一张二维码图片
        String qrcodeurl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + URLUtil.encode(ticket).replace("+", "%20");

        if ("qrurl".equalsIgnoreCase(getType)) {
            return qrcodeurl;
        }
        // 通过素材管理中的接口上传多媒体文件，得到的id
        return  doGetMediaId(access_token, qrcodeurl);
    }

    /**
     * 通过素材管理中的接口上传多媒体文件，得到的media_id
     * @param access_token
     * @param qrcodeurl 二维码图片获取地址，不用登陆也可以获取
     */
    private String doGetMediaId(String access_token, String qrcodeurl) throws Exception {
        // 将图片获取为字节流
        byte[] btImg = getImageFromNetByUrl(qrcodeurl);
        String media_id = "";
        if (null != btImg && btImg.length > 0) {
            media_id = uploadFile(access_token, btImg);
        }
        return media_id;
    }

    private String uploadFile(String access_token, byte[] btImg) throws Exception {
        String UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=image";
        String url = UPLOAD_URL.replace("ACCESS_TOKEN", access_token);
        URL urlObj = new URL(url);
        //连接
        HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
        conn.setRequestMethod("POST");
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);

        //请求头
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.setRequestProperty("Charset", "UTF-8");

        //设置边界
        String BOUNDARY = "----------" + System.currentTimeMillis();
        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
        StringBuilder sb = new StringBuilder();
        sb.append("--");
        sb.append(BOUNDARY);
        sb.append("\r\n");
        sb.append("Content-Disposition:form-data;name=\"file\";filename=\"qrcode.jpg\"\r\n");
        sb.append("Content-Type:application/octet-stream\r\n\r\n");
        byte[] head = sb.toString().getBytes("utf-8");

        // 输出流
        OutputStream out = new DataOutputStream(conn.getOutputStream());
        out.write(head);
        // 将图片文件正文部分写入
        out.write(btImg, 0, btImg.length);
        //结尾
        byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");
        out.write(foot);
        out.flush();
        out.close();
        //获取响应
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = null;
        String result = null;

        reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line = null;
        while ((line = reader.readLine()) != null) {
            buffer.append(line);
        }
        if (result == null) {
            result = buffer.toString();
        }
        reader.close();
        JSONObject json = JSONObject.parseObject(result);
        String mediaId = json.getString("media_id");
        return mediaId;
    }

    /**
     * 根据地址获得数据的字节流
     * @param strUrl 网络连接地址
     * @return
     */
    private byte[] getImageFromNetByUrl(String strUrl) {
        byte[] btImg = null;
        try {
            URL url = new URL(strUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            //通过输入流获取图片数据
            InputStream inStream = conn.getInputStream();
            //得到图片的二进制数据
            btImg = readInputStream(inStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return btImg;
    }

    /**
     * 从输入流中获取数据
     *
     * @param inStream 输入流
     * @return
     * @throws Exception
     */
    public static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        inStream.close();
        return outStream.toByteArray();
    }

    /**
     * 获取推荐二维码ticket
     * @param access_token 微信的授权码
     * @param fromUserName 操作者openid，获取人的身份，传入参数主要作用是记录这个二维码是由谁分享出去的
     */
    private String getQrCodeTicket(String access_token, String fromUserName, String regOpenid){
        String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + URLUtil.encode(access_token).replace("+", "%20");
        JSONObject object = new JSONObject();
        // 过期时间为30天，这里是最大值，该二维码有效时间，以秒为单位。 最大不超过2592000（即30天），此字段如果不填，则默认有效期为30秒。
        object.put("expire_seconds", 2592000);
        // 二维码类型，QR_SCENE为临时的整型参数值，QR_STR_SCENE为临时的字符串参数值，QR_LIMIT_SCENE为永久的整型参数值，QR_LIMIT_STR_SCENE为永久的字符串参数值
        object.put("action_name", "QR_STR_SCENE");

        JSONObject sub2 = new JSONObject();
        // 场景值ID（字符串形式的ID），字符串类型，长度限制为1到64
        String scene_str = fromUserName;
        if (StrUtil.isNotBlank(regOpenid)) {
            // 再添加小程序中的身份
            scene_str += "#" + regOpenid;
        }
        sub2.put("scene_str", scene_str);
        JSONObject sub1 = new JSONObject();
        sub1.put("scene", sub2);
        // 二维码详细信息
        object.put("action_info", sub1);
        String str = HttpUtil.post(url, object.toString());
        if (StrUtil.isBlank(str)) {
            return "";
        }
        JSONObject rest = JSONObject.parseObject(str);
        String ticket = rest.getString("ticket");
        return ticket;
    }
}
